package sk.tuke.constraintbuilder.views;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;

import sk.tuke.constraintbuilder.analyzer.RulesetManager;
import sk.tuke.constraintbuilder.editor.EditorInput;
import sk.tuke.constraintbuilder.editor.RulesetEditorController;
import sk.tuke.constraintbuilder.editor.providers.ConstraintTreeContentProvider;
import sk.tuke.constraintbuilder.editor.providers.ConstraintTreeLabelProvider;
import sk.tuke.constraintbuilder.model.Constraint;
import sk.tuke.constraintbuilder.model.Model;
import sk.tuke.constraintbuilder.model.Ruleset;
import sk.tuke.constraintbuilder.utils.MyImages;
import sk.tuke.constraintbuilder.utils.MyUtils;
import sk.tuke.constraintbuilder.views.components.RulesetEditorDNDListener;
import sk.tuke.constraintbuilder.views.components.RulesetManagerView;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.wb.swt.SWTResourceManager;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.ui.forms.widgets.Hyperlink;

public class RulesetEditorView extends Composite{

	private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
	
	//Controller
	private RulesetEditorController controller;
	
	//SWT Components
	private Form editorForm;
	private Text rulesetNameTextField;
	private Text descriptionTextField;
	private Text xmlText;
	private ListViewer rulesetViewer;
	private TreeViewer treeViewer;
	private Button editButton;
	private Label constraintNameLabel;
	private Text constraintDescriptionText;

	public RulesetEditorView(Composite parent, RulesetEditorController reController) {
		super(parent, SWT.NONE);
		this.controller=reController;
		setLayout(new FillLayout(SWT.HORIZONTAL));
		
		editorForm = toolkit.createForm(this);
		toolkit.paintBordersFor(editorForm);
		editorForm.setText("Ruleset Editor");
		editorForm.getBody().setLayout(new FillLayout(SWT.HORIZONTAL));
		
		
		//LEFT PANEL ///////////////////////////////////////////////////////////////////
		Composite leftPanel = toolkit.createComposite(editorForm.getBody(), SWT.NONE);
		toolkit.paintBordersFor(leftPanel);
		leftPanel.setLayout(new GridLayout(1, false));
		
		//Constraints in ruleset
		Section constraintsSection = toolkit.createSection(leftPanel, Section.TITLE_BAR);
		constraintsSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		toolkit.paintBordersFor(constraintsSection);
		constraintsSection.setText("Constraints in ruleset");
		constraintsSection.setExpanded(true);
		
		Composite composite = toolkit.createComposite(constraintsSection, SWT.NONE);
		toolkit.paintBordersFor(composite);
		constraintsSection.setClient(composite);
		composite.setLayout(new GridLayout(1, false));
		
		rulesetViewer = new ListViewer(composite, SWT.BORDER | SWT.V_SCROLL);
		List list = rulesetViewer.getList();
		list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		rulesetViewer.setContentProvider(ArrayContentProvider.getInstance());
		rulesetViewer.setLabelProvider(new LabelProvider() {
			@Override
			public String getText(Object element) {
				Constraint constraint = (Constraint) element;
				return String.valueOf(constraint.getName());
			};
		});
		rulesetViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				ISelection selection = rulesetViewer.getSelection();
        		if (selection != null && selection instanceof IStructuredSelection) {
        			Object obj = ((IStructuredSelection) selection).getFirstElement();
        			if (obj != null) {
        				Constraint constraint = (Constraint) obj;
        				constraintNameLabel.setText("["+constraint.getName()+"]");
        				if(constraint.getDescription()!=null){
        					constraintDescriptionText.setText(constraint.getDescription());
        				}
        				else{
        					constraintDescriptionText.setText("No description");
        				}
        				if(treeViewer!=null){
        					treeViewer.setInput(constraint);
        					treeViewer.refresh();
        				}
        				xmlText.setText("Not available");
        				editButton.setEnabled(false);
        			}
        		}
			}
		});
		int operations = DND.DROP_COPY | DND.DROP_MOVE;
		Transfer[] transferTypes = new Transfer[]{TextTransfer.getInstance()};
		rulesetViewer.addDropSupport(operations, transferTypes, new RulesetEditorDNDListener(rulesetViewer, controller));
		
		ToolBar toolbar = new ToolBar(constraintsSection, SWT.NONE);
		constraintsSection.setTextClient(toolbar);
		ToolItem removeItem = new ToolItem(toolbar, SWT.NONE);
		removeItem.setImage(MyImages.REMOVE);
		removeItem.setToolTipText("Remove selected constraint from ruleset");
		removeItem.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				IStructuredSelection selection = (IStructuredSelection) rulesetViewer.getSelection();
				Object element = selection.getFirstElement();
				if(element instanceof Constraint){
					controller.removeConstraintFromRuleset(((Constraint) element));
				}
				rulesetViewer.refresh();
			}
		});
		
		//Available constraints
		Section availableConstraintsSection = toolkit.createSection(leftPanel, Section.TITLE_BAR);
		availableConstraintsSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		toolkit.paintBordersFor(availableConstraintsSection);
		availableConstraintsSection.setText("Available Constraints");
		availableConstraintsSection.setExpanded(true);
		
		Composite composite_1 = toolkit.createComposite(availableConstraintsSection, SWT.NONE);
		toolkit.paintBordersFor(composite_1);
		availableConstraintsSection.setClient(composite_1);
		composite_1.setLayout(new GridLayout(1, false));
		
		final ListViewer constraintList = new ListViewer(composite_1, SWT.BORDER | SWT.V_SCROLL);
		List list_1 = constraintList.getList();
		list_1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		constraintList.setContentProvider(ArrayContentProvider.getInstance());
		constraintList.setLabelProvider(new LabelProvider() {
			@Override
			public String getText(Object element) {
				Constraint constraint = (Constraint) element;
				return String.valueOf(constraint.getName());
			};
		});
		constraintList.setInput(Model.getModel().getConstraints());
		constraintList.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
//				getSite().setSelectionProvider(constraintList);
				ISelection selection = constraintList.getSelection();
        		if (selection != null && selection instanceof IStructuredSelection) {
        			Object obj = ((IStructuredSelection) selection).getFirstElement();
        			if (obj != null) {
        				Constraint constraint = (Constraint) obj;
        				constraintNameLabel.setText("["+constraint.getName()+"]");
        				if(constraint.getDescription()!=null){
        					constraintDescriptionText.setText(constraint.getDescription());
        				}
        				else{
        					constraintDescriptionText.setText("No description");
        				}
        				if(treeViewer!=null){
        					treeViewer.setInput(constraint);
        					treeViewer.refresh();
        				}
        				File xml = Model.getModel().getFile(constraint.getId());
        				editButton.setEnabled(true);
        				xmlText.setText("");
        				try {
							BufferedReader reader = new BufferedReader(new FileReader(xml));
							String line = null;
							try{
								while (( line = reader.readLine()) != null){
									xmlText.append(line+"\n");
								}
							}
							finally{
								reader.close();
							}
						} 
        				catch (IOException e) {
        					/*Not show xml*/
        				}
        			}
        		}
			}
		});
		constraintList.addDragSupport(operations, transferTypes , new RulesetEditorDNDListener(constraintList, controller));
		
		toolbar = new ToolBar(availableConstraintsSection, SWT.NONE);
		availableConstraintsSection.setTextClient(toolbar);
		ToolItem refreshItem = new ToolItem(toolbar, SWT.NONE);
		refreshItem.setToolTipText("Refresh list");
		refreshItem.setImage(MyImages.REFRESH);
		refreshItem.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				constraintList.refresh();
				
			}
		});
		
		//RIGHT PANEL/////////////////////////////////////////////////////////////////
		Composite rightPanel = toolkit.createComposite(editorForm.getBody(), SWT.NONE);
		toolkit.paintBordersFor(rightPanel);
		rightPanel.setLayout(new GridLayout(1, false));
		
		//Save section
		Section saveSection = toolkit.createSection(rightPanel, Section.TWISTIE | Section.TITLE_BAR);
		saveSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
		saveSection.setBounds(0, 0, 98, 21);
		toolkit.paintBordersFor(saveSection);
		saveSection.setText("Save Ruleset");
		saveSection.setExpanded(true);
		
		Composite savePanel = toolkit.createComposite(saveSection, SWT.NONE);
		toolkit.paintBordersFor(savePanel);
		saveSection.setClient(savePanel);
		savePanel.setLayout(new GridLayout(3, false));
		
		Label descriptionLabel = new Label(savePanel, SWT.NONE);
		toolkit.adapt(descriptionLabel, true, true);
		descriptionLabel.setText("Description: ");
		
		descriptionTextField = new Text(savePanel, SWT.BORDER);
		descriptionTextField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
		toolkit.adapt(descriptionTextField, true, true);
		
		Label nameLabel = new Label(savePanel, SWT.NONE);
		nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		toolkit.adapt(nameLabel, true, true);
		nameLabel.setText("Name: ");
		
		rulesetNameTextField = new Text(savePanel, SWT.BORDER);
		rulesetNameTextField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		toolkit.adapt(rulesetNameTextField, true, true);
		
		Button saveButton = new Button(savePanel, SWT.NONE);
		saveButton.setToolTipText("Save Changes");
		toolkit.adapt(saveButton, true, true);
		saveButton.setText("Save");
		saveButton.addSelectionListener(new SelectionAdapter() {
	    	public void widgetSelected(SelectionEvent e) {
	    		controller.saveRuleset(rulesetNameTextField.getText(), descriptionTextField.getText());
	    	}
		});
				
		//Apply on project section
		Section applyRulesetSection = toolkit.createSection(rightPanel, Section.TWISTIE | Section.TITLE_BAR);
		applyRulesetSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
		applyRulesetSection.setBounds(0, 0, 98, 21);
		toolkit.paintBordersFor(applyRulesetSection);
		applyRulesetSection.setText("Apply Ruleset on project");
		applyRulesetSection.setExpanded(true);
		
		Composite composite_3 = toolkit.createComposite(applyRulesetSection, SWT.NONE);
		toolkit.paintBordersFor(composite_3);
		applyRulesetSection.setClient(composite_3);
		composite_3.setLayout(new GridLayout(2, false));
		
		Button btnSelectProject = new Button(composite_3, SWT.NONE);
		btnSelectProject.setToolTipText("Apply ruleset on projects");
		toolkit.adapt(btnSelectProject, true, true);
		btnSelectProject.setText("Select project..");
		btnSelectProject.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
	    		final ListSelectionDialog dlg = new ListSelectionDialog(getShell(), ResourcesPlugin.getWorkspace().getRoot(), new BaseWorkbenchContentProvider(), new WorkbenchLabelProvider(), "Select the Project:");
	    		dlg.setTitle("Project Selection");
	    		dlg.open();
	    		for (Object project : dlg.getResult()) {
					if(project instanceof IProject){
						if(controller.saveRuleset(rulesetNameTextField.getText(), descriptionTextField.getText()))
							RulesetManager.getInstance().applyRulesetOnProject((IProject)project, controller.getRuleset());
					}
				}
			}
		});
		
		
		new ArrayList<>();
		Button btnRulesetManager = new Button(composite_3, SWT.NONE);
		btnRulesetManager.setToolTipText("Ruleset Manager");
		toolkit.adapt(btnRulesetManager, true, true);
		btnRulesetManager.setText("Ruleset Manager..");
		btnRulesetManager.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				controller.saveRuleset(rulesetNameTextField.getText(), descriptionTextField.getText());
	    		new RulesetManagerView(getShell()).open();
			}
		});
		
		//Constraint view
		Section constraintViewSection = toolkit.createSection(rightPanel, Section.TWISTIE | Section.TITLE_BAR);
		constraintViewSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		constraintViewSection.setBounds(0, 0, 98, 21);
		toolkit.paintBordersFor(constraintViewSection);
		constraintViewSection.setText("Constraint View");
		constraintViewSection.setExpanded(true);
		
		Composite constraintViewPanel = toolkit.createComposite(constraintViewSection, SWT.NONE);
		toolkit.paintBordersFor(constraintViewPanel);
		constraintViewSection.setClient(constraintViewPanel);
		constraintViewPanel.setLayout(new GridLayout(1, false));
		
		constraintNameLabel = new Label(constraintViewPanel, SWT.NONE);
		constraintNameLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
		toolkit.adapt(constraintNameLabel, true, true);
		constraintNameLabel.setText("[Constraint Name]");
		
		TabFolder tabFolder = new TabFolder(constraintViewPanel, SWT.NONE);
		tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		toolkit.adapt(tabFolder);
		toolkit.paintBordersFor(tabFolder);
		
		TabItem descriptionTab = new TabItem(tabFolder, SWT.NONE);
		descriptionTab.setText("Description");
		constraintDescriptionText = new Text(tabFolder, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.READ_ONLY);
		descriptionTab.setControl(constraintDescriptionText);
		
		TabItem treeTab = new TabItem(tabFolder, SWT.NONE);
		treeTab.setText("Tree");
	    treeViewer = new TreeViewer(tabFolder,SWT.BORDER | SWT.V_SCROLL);
	    treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
	    treeViewer.setContentProvider(new ConstraintTreeContentProvider());
	    treeViewer.setLabelProvider(new ConstraintTreeLabelProvider());
	    treeTab.setControl(treeViewer.getControl());
		
		TabItem xmlTab = new TabItem(tabFolder, SWT.NONE);
		xmlTab.setText("XML");
	    xmlText = new Text(tabFolder, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.READ_ONLY);
	    xmlText.setText("");
	    xmlTab.setControl(xmlText);
		
		editButton = new Button(rightPanel, SWT.NONE);
		toolkit.adapt(editButton, true, true);
		editButton.setText("Edit Constraint");
	    editButton.setEnabled(false);
		editButton.addSelectionListener(new SelectionAdapter() {
	    	public void widgetSelected(SelectionEvent e) {
	    		String ID = MyUtils.getFirstIDFromSelection(constraintList.getSelection());
	    		controller.callConstraintEditor(ID);
	    	}
		});
	}

	public void showRuleset(Ruleset ruleset) {
		rulesetViewer.setInput(ruleset.getConstraints());
		rulesetNameTextField.setText(ruleset.getName());
		if(ruleset.getDescription()!=null){
			descriptionTextField.setText(ruleset.getDescription());
		}
		editorForm.setText("Ruleset: "+ruleset.getName());
	}
}
